package com.shanghaionstar.utils;

import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.location.LocationManagerProxy;
import com.amap.api.location.LocationProviderProxy;
import com.onstar.cn.common.log.LogManager;

import java.util.Timer;
import java.util.TimerTask;

/**
 *
 * @ClassName: MyLocationUtil
 * @author Xiaofeng Feng
 * @date 2015-08-06 下午4:21:14
 */
public class MyLocationUtil {
	private static final String TAG = "*MyLocationUtil*";
	private static LogManager logger = LogManager.getInstance();
	private Context context;
	private boolean gpsEnabled = false;
	private boolean netWorkEnabled = false;
	private Timer timer;
	private LocationResult locationResult;
	Handler mHandler = new Handler();

	private static final int CHECK_INTERVAL = 1000 * 5;
	private Location currentLocation = null;
	private LocationListenerProxy llp;
	private int updateCount = 0;
	private int updateCountLimit = 2;// update location次数上限
	private int timerCount = 0;
	private int timerCountLimit = 9;// 超时时间设置
	private double accuracyLimit = 100;// 精度要求
	private boolean isFirstLocation = false;

	private final LocationManagerProxy locationManager;

	public MyLocationUtil(Context context, LocationResult locationResult) {
		this.context = context;
		this.locationResult = locationResult;
		locationManager = LocationManagerProxy.getInstance(context);
		llp = new LocationListenerProxy(locationManager);
		logger.d("==============isGpsEnabled=" + isGpsEnabled());
		logger.d("==============isNetWorkEnabled=" + isNetWorkEnabled());
	}

	/**
	 *
	 *
	 * @Title: initMyLocation
	 * @Description: 初始化变量，并开始定位手机位置
	 * @return void 返回类型
	 * @throws
	 */
	public void initMyLocation() {
        updateCount = 0;
        timerCount = 0;
        currentLocation = null;
        boolean locating = llp.startListening(mListener, 0, 0);
        if (locating) {
            timer = new Timer();
            timer.schedule(new MyGetLastLocation(), 0, 1000 * 5);
        } else {
            locationResult.gotLocation(null);
        }
    }

	public boolean getMyLocation() {
		isFirstLocation = true;
		updateCount = 0;
		timerCount = 0;
		currentLocation = null;
		boolean locating = llp.startListening(mListener, 0, 0);
		if (locating && (isGpsEnabled() || isNetWorkEnabled())) {
			timer = new Timer();
			timer.schedule(new MyGetLastLocation(), 0, 1000 * 5);
		}
		return locating && (isGpsEnabled() || isNetWorkEnabled());
	}

	public void disableMyLocation() {
		llp.stopListening();
		locationManager.removeUpdates(llp);
		locationManager.removeUpdates(mListener);
		if (timer != null) {
			timer.cancel();
		}
	}

	AMapLocationListener mListener = new AMapLocationListener() {

		@Override
		@Deprecated
		public void onLocationChanged(Location location) {
		}

		@Override
		public void onProviderDisabled(String arg0) {
		}

		@Override
		public void onProviderEnabled(String arg0) {
		}

		@Override
		public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
		}

		@Override
		public void onLocationChanged(AMapLocation location) {
			if (isFirstLocation) {
				isFirstLocation = false;
				locationResult.gotLocation(location);
				llp.stopListening();
				locationManager.removeUpdates(llp);
				locationManager.removeUpdates(mListener);
				locationResult.gotLocation(location);
				return;
			}

			String provider = location.getProvider();
			logger.d("==============updateCount=" + updateCount);
			logger.d("==============Location Accuracy=" + location.getAccuracy() + " provider=" + provider);
			if (currentLocation != null) {
				if (isBetterLocation(location, currentLocation)) {
					logger.d("It's a better location");
					currentLocation = location;
					if (locationResult != null) {
						if (currentLocation.getAccuracy() < accuracyLimit
								|| updateCount > updateCountLimit
								|| (!isGpsEnabled() && provider.equalsIgnoreCase(LocationProviderProxy.AMapNetwork) && provider
										.equalsIgnoreCase(currentLocation.getProvider()))) {
							llp.stopListening();
							locationManager.removeUpdates(llp);
							locationManager.removeUpdates(mListener);
							locationResult.gotLocation(location);
							if (null != timer)
								timer.cancel();
						}
					}
				} else {
					if (updateCount >= updateCountLimit
							|| (!isGpsEnabled() && provider.equalsIgnoreCase(LocationProviderProxy.AMapNetwork) && provider
									.equalsIgnoreCase(currentLocation.getProvider()))) {
						logger.d("Not very good! But updateCount > updateCountLimit Or provider is"
								+ LocationProviderProxy.AMapNetwork);
						llp.stopListening();
						locationManager.removeUpdates(llp);
						locationManager.removeUpdates(mListener);
						locationResult.gotLocation(location);
						if (null != timer)
							timer.cancel();
					}
					logger.d("Not very good!");
				}
			} else {
				logger.d("==============It's first location");
				currentLocation = location;
				if (locationResult != null) {
					if (currentLocation.getAccuracy() < accuracyLimit
							|| (!isGpsEnabled() && currentLocation.getAccuracy() < accuracyLimit + 100)) {
						logger.d("==============It's first location and it's good enough or isGpsEnabled="
								+ isGpsEnabled());
						llp.stopListening();
						locationManager.removeUpdates(llp);
						locationManager.removeUpdates(mListener);
						locationResult.gotLocation(location);
						if (null != timer)
							timer.cancel();
					}
				}
			}
			updateCount++;
		}
	};

	public static abstract class LocationResult {
		public abstract void gotLocation(Location location);
	}

	public boolean isGpsEnabled() {
		gpsEnabled = locationManager.isProviderEnabled(LocationManagerProxy.GPS_PROVIDER);
		return gpsEnabled;
	}

	public boolean isNetWorkEnabled() {
		netWorkEnabled = locationManager.isProviderEnabled(LocationProviderProxy.AMapNetwork);
		return netWorkEnabled;
	}

	/**
	 *
	 *
	 * @Title: initVariable
	 * @Description: 初始换变量
	 * @return void 返回类型
	 * @throws
	 */
	public void initVariable() {
		currentLocation = null;
		updateCount = 0;
		timerCount = 0;
		llp.stopListening();
		locationManager.removeUpdates(llp);
		locationManager.removeUpdates(mListener);
		if (timer != null) {
			timer.cancel();
		}
	}

	protected boolean isBetterLocation(Location location, Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > CHECK_INTERVAL;
		boolean isSignificantlyOlder = timeDelta < -CHECK_INTERVAL;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location,
		// use the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must
			// be worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return true;
		}
		return false;
	}

	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	class MyGetLastLocation extends TimerTask {
		@Override
		public void run() {
			logger.d("==============TimerTask timerCount=" + timerCount);
			if (timerCount > timerCountLimit) // 15秒之后超时
			{
				if (null != currentLocation) {
					logger.d("==============" + (timerCountLimit + 1) + "秒后，无法获得更精确值，取现有值");
					locationResult.gotLocation(currentLocation);
				} else {
					locationResult.gotLocation(null);
					logger.d("==============" + (timerCountLimit + 1) + "秒后定位超时，无法获得当前位置");
				}
				llp.stopListening();
				locationManager.removeUpdates(llp);
				locationManager.removeUpdates(mListener);
				this.cancel();
				timer.cancel();
			}
			timerCount++;
		}
	}

}
